Skip to content

Release v1.16.0#25

Merged
bethropolis merged 19 commits into
mainfrom
dev/next
Jul 14, 2026
Merged

Release v1.16.0#25
bethropolis merged 19 commits into
mainfrom
dev/next

Conversation

@bethropolis

Copy link
Copy Markdown
Owner

RemoteSystemVolume plugin, clipboard fixes, SFTP browse, device auto-prune.

  • feat: add RemoteSystemVolume plugin (kcd volume)
  • feat: clipboard push-on-connect opt-in (default off)
  • feat: auto-prune stale unpaired devices
  • feat: kcd sftp browse subcommand
  • feat: Docker Alpine image
  • fix: clipboard backend detection when WAYLAND_DISPLAY unset
  • fix: auto-reconnect CPU spin from backoff overflow
  • docs: IPC protocol, client guide, CLI reference

…me method

mountWithBody now accepts an optional volumePath parameter. When empty,
existing behaviour is preserved (auto-select first volume from multiPaths).

RequestAndMountVolume follows the same subscribe-request-wait pattern as
RequestAndMount but accepts a specific volume path to mount. If the path
is empty, available volumes are returned without mounting (list mode).

Extracted buildVolumes helper to avoid duplicating the volume-building
logic in Volumes() and the new method.
Adds sftp_browse IPC command with volume resolution logic (index, name,
or path matching). The daemon handler requests fresh credentials, then
either lists volumes or mounts the chosen one via sshfs.

New IPC types:
  - CmdSftpBrowse constant
  - SftpBrowsePayload (deviceId + optional volume)
  - SftpBrowseResponse (optional path + volumes)

New client method:
  - SftpBrowse(deviceID, volume) returns (mountPath, volumes, err)

CLI:
  - kcd sftp browse <device-id>      list volumes (fresh creds)
  - kcd sftp browse <device-id> <v>  mount volume by index/name/path
Adds two new reference documents:
  - docs/IPC_PROTOCOL.md — complete wire protocol reference (28 commands,
    27 event types, packet tables, walkthroughs)
  - docs/CLIENT_GUIDE.md — client developer guide with Python examples,
    feature patterns, and integration templates

Updates docs/CLI.md:
  - Adds sftp browse subcommand docs
  - Adds mpris raw section
  - Fills event type table with 6 previously missing types
  - Fixes share.complete payload schema

Updates packaging/kcd.fish-completion:
  - Adds missing event types to watch --events completions

Updates AGENTS.md:
  - Adds step 8 to plugin checklist (documentation requirement)
The install hook printed a message on every package update which was
annoying for users. Removing the reference skips it entirely.
Adds automatic cleanup of stale devices from the registry. Devices that are
neither paired nor connected are removed when their last-seen timestamp
exceeds the threshold (default: 15m). This prevents old discovery entries
from accumulating in `kcd devices` and `devices.json`.

- LastSeen is now refreshed on every TCP connection (handleNewConnection)
  so active/reconnecting devices stay alive
- Prune runs at daemon startup and before every saveDevices write
- New config key: prune_stale_threshold (Go duration format, '0' to disable)
- Silent cleanup — no events published for pruned devices
Adds result/ to .gitignore and restores flake.lock after Nix build
step to prevent git dirty state error in GoReleaser.
git checkout flake.lock only restores from the index, but if
Nix also stages the file, the index copy is still dirty.
Using git checkout HEAD -- flake.lock properly discards
both staged and working-tree changes.
Keep HEAD -- flake.lock over plain flake.lock to properly
discard staged changes.
Nix build creates flake.lock and a result symlink, which dirties
the git tree and blocks GoReleaser's --clean check. Moving Nix
steps to a separate workflow triggered by workflow_run eliminates
this conflict entirely.
ReconnectBackoff shift overflowed int64 at attempt >= 54, returning 0
instead of capping, causing time.After(0) to fire immediately in a
tight loop (25% CPU on one core).

Fix 1: cap attempt at 31 before shift to avoid overflow entirely.
Fix 2: add reconnecting guard to Device via atomic.Bool to prevent
multiple concurrent reconnect goroutines from piling up.
systemd user services don't inherit desktop env vars, so
os.Getenv("WAYLAND_DISPLAY") was always empty, forcing xclip
even under Wayland.

Replace static isWayland bool with detectBackend() that probes
exec.LookPath("wl-paste") -> exec.LookPath("xclip") at first
use, cached via sync.Once.

Also log Warn when wl-copy/xclip fails instead of silent discard.
New plugin for controlling phone audio volume from the CLI —
the inverse of the existing SystemVolume plugin (phone controls
PC volume).

- Handles incoming kdeconnect.systemvolume (sink list + per-sink
  updates from phone), sends kdeconnect.systemvolume.request
  (volume/mute commands to phone)
- Caches sink list per-device via sync.Map; OnConnect auto-requests
  sink list
- IPC: remote_volume_list, remote_volume_set, remote_volume_mute
- CLI: kcd volume list/set/mute subcommands
- Events: reuses volume.update for both per-sink and full sink-list
  payloads
- Default: enabled (remotesystemvolume = true)
Under systemd user services, neither WAYLAND_DISPLAY nor DISPLAY
is inherited from the login session. detectBackend() only checked
exec.LookPath, found wl-paste, and committed to the Wayland backend
— but wl-paste then defaulted to the wrong socket (wayland-0) and
failed with exit code 1.

Fix: check display environment variables first, then probe
/run/user/1000 for any wayland-* socket before selecting the
Wayland backend. X11 remains the fallback when no socket is found.
Adds [clipboard] config section with push_on_connect option
(default false). When true, the local clipboard is pushed to a
device every time it connects/reconnects via OnConnect. When
false (default), clipboard is only pushed explicitly via
kcd clipboard.
@bethropolis
bethropolis merged commit 7151347 into main Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant